var input = File.ReadAllLines(Path.Combine(Path.GetDirectoryName(Util.CurrentQueryPath), "..", "day21.txt")); var rules = input.Select(i => i.Split(new[] { " => " }, StringSplitOptions.None)) .Select(i => new { Input = i[0].Split('/'), Output = i[1].Split('/') }) .SelectMany(r => keys(r.Input).Select(ru => new { pattern = ru, r.Output })) .ToDictionary(r => r.pattern, r => r.Output); string[][] patterns(string[] block) => new[] { block, rotate(block), rotate(rotate(block)), rotate(rotate(rotate(block))), flip(block), flip(rotate(block)), flip(rotate(rotate(block))), flip(rotate(rotate(rotate(block)))) }; string[] keys(string[] block) => patterns(block).Select(c => c.Aggregate((s, a) => s + a)).Distinct().ToArray(); var image = new[] { ".#.", "..#", "###" }; string[] rotate(string[] b) { return b.Length == 2 ? new[] { new string(new[] { b[1][0], b[0][0] }), new string(new[] { b[1][1], b[0][1] }) } : new[] { new string(new[] { b[2][0], b[1][0], b[0][0] }), new string(new[] { b[2][1], b[1][1], b[0][1] }), new string(new[] { b[2][2], b[1][2], b[0][2] }) }; } string[] flip(string[] b) => b.Reverse().ToArray(); IEnumerable getBlock(string[] source, int rw, int c, int s) => Enumerable.Range(0, s).Select(r => source[rw * s + r].Substring(c * s, s)); string[] grow(string[] source) { var size = source.Length; var blocksize = size % 2 == 0 ? 2 : 3; var blocks = size / blocksize; var output = new string[(blocks) * (blocksize + 1)]; for (var row = 0; row < blocks; row++) for (var col = 0; col < blocks; col++) { var b = rules[getBlock(source,row,col,blocksize).Aggregate((sd, a) => sd + a)]; for (var i = 0; i < b.Length; i++) { output[row * b.Length + i] += b[i]; } } return output; } for (int iterations = 0; iterations < 5; iterations++) image = grow(image); var part1 = image.Sum(i => i.ToCharArray().Count(c => c == '#')); part1.Dump(); for (int iterations = 5; iterations < 18; iterations++) image = grow(image); var part2 = image.Sum(i => i.ToCharArray().Count(c => c == '#')); part2.Dump();